﻿package com.sgcc.nfc.lock.presentation.region

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.sgcc.nfc.lock.core.network.NetworkResult
import com.sgcc.nfc.lock.domain.model.Region
import com.sgcc.nfc.lock.domain.model.RegionLevel
import com.sgcc.nfc.lock.domain.model.RoleType
import com.sgcc.nfc.lock.domain.model.UserProfile
import com.sgcc.nfc.lock.domain.repository.RegionRepository
import com.sgcc.nfc.lock.domain.usecase.CreateRegionUseCase
import com.sgcc.nfc.lock.domain.usecase.DeleteRegionUseCase
import com.sgcc.nfc.lock.domain.usecase.GetProfileUseCase
import com.sgcc.nfc.lock.domain.usecase.GetRegionTreeUseCase
import com.sgcc.nfc.lock.domain.usecase.UpdateRegionUseCase
import com.sgcc.nfc.lock.presentation.common.EventFlow
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.launch

@HiltViewModel
class RegionManagementViewModel @Inject constructor(
    private val getRegionTreeUseCase: GetRegionTreeUseCase,
    private val createRegionUseCase: CreateRegionUseCase,
    private val updateRegionUseCase: UpdateRegionUseCase,
    private val deleteRegionUseCase: DeleteRegionUseCase,
    private val getProfileUseCase: GetProfileUseCase
) : ViewModel() {

    private val _uiState = MutableLiveData(RegionTreeUiState(isLoading = true))
    val uiState: LiveData<RegionTreeUiState> = _uiState

    private val _events = EventFlow<RegionEvent>()
    val events = _events.events

    private var regionTree: List<Region> = emptyList()
    private val regionIndex = mutableMapOf<Long, Region>()
    private val expandedIds = mutableSetOf<Long>()
    private var pendingFocusRegionId: Long? = null
    private var currentUser: UserProfile? = null
    private var currentUserLoaded = false

    init {
        refresh()
    }

    fun refresh() {
        loadRegions()
    }

    private fun loadRegions() {
        _uiState.update { it.copy(isLoading = true, error = null) }
        viewModelScope.launch {
            ensureCurrentUser()
            when (val result = getRegionTreeUseCase()) {
                is NetworkResult.Success -> {
                    val accessibleTree = applyAccessControl(result.data)
                    regionTree = accessibleTree
                    rebuildRegionIndex(accessibleTree)
                    if (expandedIds.isEmpty()) {
                        expandedIds.addAll(regionTree.map { it.regionId })
                    }
                    pendingFocusRegionId?.let { expandedIds.add(it) }
                    pendingFocusRegionId = null
                    _uiState.update {
                        it.copy(
                            isLoading = false,
                            items = flattenTree(regionTree),
                            error = null
                        )
                    }
                }
                is NetworkResult.Error -> {
                    _uiState.update {
                        it.copy(
                            isLoading = false,
                            items = emptyList(),
                            error = result.message
                        )
                    }
                    result.message?.let { message ->
                        viewModelScope.launch { _events.emit(RegionEvent.ShowMessage(message)) }
                    }
                }
                NetworkResult.Loading -> Unit
            }
        }
    }

    fun toggleRegion(regionId: Long) {
        if (expandedIds.contains(regionId)) {
            expandedIds.remove(regionId)
        } else {
            expandedIds.add(regionId)
        }
        _uiState.update { it.copy(items = flattenTree(regionTree)) }
    }

    fun createRegion(name: String, type: Int, parentId: Long) {
        viewModelScope.launch {
            when (val result = createRegionUseCase(
                RegionRepository.CreateRegionParams(
                    regionName = name,
                    regionType = type,
                    parentId = parentId
                )
            )) {
                is NetworkResult.Success -> {
                    pendingFocusRegionId = parentId.takeIf { it > 0 }
                    _events.emit(RegionEvent.OperationSuccess(RegionEvent.OperationType.CREATE))
                    _events.emit(RegionEvent.FormSubmitted)
                    loadRegions()
                }
                is NetworkResult.Error -> {
                    _events.emit(RegionEvent.ShowMessage(result.message ?: "Operation failed"))
                }
                NetworkResult.Loading -> Unit
            }
        }
    }

    fun updateRegion(regionId: Long, name: String, type: Int, parentId: Long) {
        viewModelScope.launch {
            when (val result = updateRegionUseCase(
                RegionRepository.UpdateRegionParams(
                    regionId = regionId,
                    regionName = name,
                    regionType = type,
                    parentId = parentId
                )
            )) {
                is NetworkResult.Success -> {
                    pendingFocusRegionId = parentId.takeIf { it > 0 }
                    _events.emit(RegionEvent.OperationSuccess(RegionEvent.OperationType.UPDATE))
                    _events.emit(RegionEvent.FormSubmitted)
                    loadRegions()
                }
                is NetworkResult.Error -> {
                    _events.emit(RegionEvent.ShowMessage(result.message ?: "Operation failed"))
                }
                NetworkResult.Loading -> Unit
            }
        }
    }

    fun deleteRegion(regionId: Long) {
        viewModelScope.launch {
            when (val result = deleteRegionUseCase(regionId)) {
                is NetworkResult.Success -> {
                    expandedIds.remove(regionId)
                    _events.emit(RegionEvent.OperationSuccess(RegionEvent.OperationType.DELETE))
                    loadRegions()
                }
                is NetworkResult.Error -> {
                    _events.emit(RegionEvent.ShowMessage(result.message ?: "Operation failed"))
                }
                NetworkResult.Loading -> Unit
            }
        }
    }

    private fun flattenTree(tree: List<Region>): List<RegionListItem> {
        val items = mutableListOf<RegionListItem>()
        tree.forEach { appendRegion(it, 0, items) }
        return items
    }

    private fun appendRegion(region: Region, depth: Int, items: MutableList<RegionListItem>) {
        val hasChildren = region.children.isNotEmpty()
        val isExpanded = expandedIds.contains(region.regionId)
        val canManage = canManageRegion(region)
        val canAddChild = canManage && childLevelsForParent(region.regionId).isNotEmpty()
        val canDelete = canManage && !hasChildren
        items += RegionListItem(
            region = region,
            depth = depth,
            isExpanded = isExpanded,
            hasChildren = hasChildren,
            canManage = canManage,
            canAddChild = canAddChild,
            canEdit = canManage,
            canDelete = canDelete
        )
        if (hasChildren && isExpanded) {
            region.children.forEach { child -> appendRegion(child, depth + 1, items) }
        }
    }

    fun currentTree(): List<Region> = regionTree

    fun canManageRoot(): Boolean = roleType() == RoleType.SUPER_ADMIN

    fun defaultParentId(): Long = when (roleType()) {
        RoleType.SUPER_ADMIN -> 0L
        else -> currentUser?.regionId ?: 0L
    }

    fun regionLevel(region: Region?): RegionLevel? =
        region?.let { RegionLevel.fromValue(it.regionType ?: it.level) }

    fun childLevelsForParent(parentId: Long): List<RegionLevel> {
        val parentLevel = when {
            parentId == 0L -> RegionLevel.HEADQUARTERS
            else -> findRegionById(parentId)?.let(::regionLevel)
        } ?: return emptyList()
        return when (parentLevel) {
            RegionLevel.HEADQUARTERS -> listOfNotNull(RegionLevel.PROVINCE)
            RegionLevel.PROVINCE -> listOfNotNull(RegionLevel.CITY)
            RegionLevel.CITY -> listOfNotNull(RegionLevel.COUNTY, RegionLevel.STATION)
            RegionLevel.COUNTY -> listOfNotNull(RegionLevel.STATION)
            RegionLevel.STATION -> emptyList()
        }
    }

    fun childLevelForParent(parentId: Long): RegionLevel? =
        childLevelsForParent(parentId).firstOrNull()

    fun findRegionById(id: Long): Region? = regionIndex[id]

    fun canManageRegionId(id: Long): Boolean =
        findRegionById(id)?.let(::canManageRegion) ?: false

    private inline fun MutableLiveData<RegionTreeUiState>.update(transform: (RegionTreeUiState) -> RegionTreeUiState) {
        val current = value ?: RegionTreeUiState()
        value = transform(current)
    }

    private suspend fun ensureCurrentUser() {
        if (currentUserLoaded) return
        when (val result = getProfileUseCase()) {
            is NetworkResult.Success -> currentUser = result.data
            is NetworkResult.Error -> {
                result.message?.let { message -> _events.emit(RegionEvent.ShowMessage(message)) }
            }
            NetworkResult.Loading -> Unit
        }
        currentUserLoaded = true
    }

    private fun applyAccessControl(tree: List<Region>): List<Region> {
        val role = roleType()
        if (role == null || role == RoleType.SUPER_ADMIN) {
            return tree
        }
        val userRegionId = currentUser?.regionId ?: return tree
        val target = findRegionRecursive(tree, userRegionId) ?: return tree
        return listOf(target)
    }

    private fun rebuildRegionIndex(tree: List<Region>) {
        regionIndex.clear()
        fun walk(region: Region) {
            regionIndex[region.regionId] = region
            region.children.forEach(::walk)
        }
        tree.forEach(::walk)
    }

    private fun findRegionRecursive(regions: List<Region>, targetId: Long): Region? {
        regions.forEach { region ->
            if (region.regionId == targetId) return region
            val childMatch = findRegionRecursive(region.children, targetId)
            if (childMatch != null) return childMatch
        }
        return null
    }

    private fun canManageRegion(region: Region): Boolean {
        val role = roleType()
        if (role == null || role == RoleType.SUPER_ADMIN) {
            return true
        }
        val userRegionId = currentUser?.regionId ?: return false
        val levelPath = region.levelPath ?: return false
        return levelPath.split('/').contains(userRegionId.toString())
    }

    private fun roleType(): RoleType? = RoleType.fromValue(currentUser?.roleType)
}

